/*
 *  MTouchware_handlers.c
 *
 *  This code handles received messages via the TUIO_receiver.
 *
 *  Copyright (C) 2010 LIMSI-CNRS (Orsay-France) and EFREI (Paris-France)
 *
 *  Authors: Rami Ajaj, Nicolas Flasque and Frederic Vernier.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as
 *  published by the Free Software Foundation; either version 2.1 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  $Id$
 */

#include "MTouchware_handlers.h"
#include "MTouchware_touch.h"
#include "MTouchware_services.h"

/* catch any incoming messages and display them. returning 1 means that the
 * message has not been fully handled and the server should try other methods */
int generic_handler(const char *path, const char *types, lo_arg **argv,
                    int argc, void *data, void *user_data)
{

    int cpt;
#ifdef VERBOSE
    int nf_argnum;
#endif

    t_applicationData *appData = (t_applicationData *)user_data;

	if (strcmp(&argv[0]->s,"source")==0) // source message : just keep source in appData to resend later from output values
	{
#ifdef VERBOSE
		printf("GENERIC HANDLER path: <%s> SOURCE\n", path);
		printf("                types <%s> \n",types);
		printf("                args  <%s %s>\n",&argv[0]->s,&argv[1]->s);
#endif
        strcpy(appData->source,&argv[1]->s);

        // check for tuioformat for sending data

        if (appData->input.first == 1)
        {
            // check for path and extract format
            appData->tuioformat = get_tuio_format_from_string(path);
            printf("found tuio format : %d\n",appData->tuioformat);
        }

		//send_message(path,types,&argv[0]->s,&argv[1]->s);
	}
	else if (strcmp(&argv[0]->s,"alive")==0)
	{
#ifdef VERBOSE
        printf("GENERIC HANDLER path: <%s> ALIVE\n", path);
        printf("                types <%s> \n",types);
        printf("                args  <%s",&argv[0]->s);

        for(nf_argnum=1;nf_argnum<argc;nf_argnum++)
        {
            printf(" %d",argv[nf_argnum]->i);
        }
        printf(">\n");
#endif
        // store alive list in appData

        // get currentIndex and set it

        int previdx, idx;

        if (appData->input.first == 0) // not first time, so there is a previous info and index
        {
            previdx = appData->input.currentIndex;
            idx = (previdx+1)%INPUT_TAB_SIZE;
        }
        else // first time
        {
            idx = 0;
        }

        appData->input.currentIndex = idx;

        t_touches *curTouches = &(appData->input.touchdata[idx]);
        curTouches->nbTouchInfo = argc-1; // number of active touches inside the list
        // fill alive list with OSC alive message values

        for(cpt=1; cpt < argc; cpt++)
        {
                curTouches->alivelist[cpt-1] = (argv[cpt]->i);
        }
        curTouches->time = 0.0f;

        curTouches->touchInfoTab = (p_touch_info)malloc((argc-1)*sizeof(t_touch_info));

        // setting touch status wrt previous alive list

        if (appData->input.first == 1) // first time, set status to ADDED
        {
                appData->input.first = 0;
                for (cpt=0; cpt < curTouches->nbTouchInfo;cpt++)
                {
                        curTouches->touchInfoTab[cpt].input_status = ADDED_NOW; // tuio status : added
                        curTouches->touchInfoTab[cpt].prev = NULL;
                }
        }
        else
        {
            // search for same touch in previous alive list(s)

            t_touches *prevTouches = &(appData->input.touchdata[previdx]);

            for (cpt=0; cpt < curTouches->nbTouchInfo;cpt++)
            {
                int foundinprev = 0;
                int cptprev = 0;

                // just search in previous alive list
                // CAUTION : there may not be a SET message for each ALIVE tuio container
                // so we mark container as NOT_IN_CURRENT_BUNDLE by default

                while ((!foundinprev) && (cptprev < prevTouches->nbTouchInfo))
                {
                    foundinprev = (curTouches->alivelist[cpt] == prevTouches->alivelist[cptprev]);
                    cptprev++;
                }

                if (foundinprev)
                {
                        curTouches->touchInfoTab[cpt].input_status = NOT_IN_CURRENT_BUNDLE; // not yet found, because the SET messages haven't been processed so far
                        curTouches->touchInfoTab[cpt].prev = &(prevTouches->touchInfoTab[cptprev-1]);
                        curTouches->touchInfoTab[cpt].pvalues = (curTouches->touchInfoTab[cpt].prev)->pvalues;
                }
                else // new touch
                {
                        curTouches->touchInfoTab[cpt].input_status = ADDED_NOW;
                        curTouches->touchInfoTab[cpt].prev = NULL;
                }
            }

        }

		//send_message_lo_args(path,types,argv);
	}
	else if (strcmp(&argv[0]->s,"fseq")==0)
	{
#ifdef VERBOSE
        printf("GENERIC HANDLER path: <%s> FSEQ %d \n", path, argv[1]->i);
        printf("                types <%s> \n",types);
		printf("                args  <%s %d>\n\n",&argv[0]->s,argv[1]->i);
#endif
        //debugDisplay(appData);
        processData(appData);
		//send_message(path,types,&argv[0]->s,argv[1]->i);
	}
#ifdef VERBOSE
    fflush(stdout);
#endif
  return 1;
}

//Handler for message /tuio/2Dcur set s x y X Y m.
int tuio2Dcur_handler(const char *path, const char *types, lo_arg **argv, int argc,
                      void *data, void *user_data)
{
    // retrieve application data and fill current input info with OSC set message for 2Dcursors
    t_applicationData *appData = (t_applicationData *)user_data;

    // lumio sends 2DCUR so use 2D cursor handler function for testing algos

    int sessionID = argv[1]->i;
    p_touches curTouches = &(appData->input.touchdata[appData->input.currentIndex]);

    int nbTouches = curTouches->nbTouchInfo;

    // search for sessionID in ALIVE_LIST

    int index =0;
    int found = 0;

    while ((!found) && (index < nbTouches))
    {
            found = (sessionID == curTouches->alivelist[index]);
            index++;
    }

    if (!found)
    {
            printf("fatal error : sessionID not found in active Cursor list !\n");
            exit(-1);
    }
    else
    {
            index--;
            // update the cursor status to UPDATED_NOW
            if (curTouches->touchInfoTab[index].input_status == NOT_IN_CURRENT_BUNDLE)
            {
                    curTouches->touchInfoTab[index].input_status = UPDATED_NOW;
            }
    }

    // now copy other values in touch_info
    p_touch_values curValues = (p_touch_values)malloc(sizeof(t_touch_values));

    initValues(curValues);

    curTouches->touchInfoTab[index].pvalues = curValues;

    curValues->session_id = sessionID;
    curValues->where.x = argv[2]->f;
    curValues->where.y = argv[3]->f;
    curValues->speed.sx = argv[4]->f;
    curValues->speed.sy = argv[5]->f;
    curValues->motionAccel = argv[6]->f;

	//send_message(path,types,&argv[0]->s,argv[1]->i,argv[2]->f,argv[3]->f,argv[4]->f,argv[5]->f,argv[6]->f);
	/* example showing pulling the argument values out of the argv array */
	//printf("%s <- %s %d %f %f %f %f %f \n\n", path,&argv[0]->s,argv[1]->i,argv[2]->f,argv[3]->f,argv[4]->f,argv[5]->f,argv[6]->f);
  //fflush(stdout);


  return 0;
}

//Handler for message /tuio/25Dcur set s x y z X Y Z m.
int tuio25Dcur_handler(const char *path, const char *types, lo_arg **argv, int argc,
                       void *data, void *user_data)
{
	    // retrieve application data and fill current input info with OSC set message for 2Dcursors
    t_applicationData *appData = (t_applicationData *)user_data;

    // lumio sends 2DCUR so use 2D cursor handler function for testing algos

    int sessionID = argv[1]->i;
    p_touches curTouches = &(appData->input.touchdata[appData->input.currentIndex]);

    int nbTouches = curTouches->nbTouchInfo;

    // search for sessionID in ALIVE_LIST

    int index =0;
    int found = 0;

    while ((!found) && (index < nbTouches))
    {
            found = (sessionID == curTouches->alivelist[index]);
            index++;
    }

    if (!found)
    {
            printf("fatal error : sessionID not found in active Cursor list !\n");
            exit(-1);
    }
    else
    {
            index--;
            // update the cursor status to UPDATED_NOW
            if (curTouches->touchInfoTab[index].input_status == NOT_IN_CURRENT_BUNDLE)
            {
                    curTouches->touchInfoTab[index].input_status = UPDATED_NOW;
            }
    }

    // now copy other values in touch_info
    p_touch_values curValues = (p_touch_values)malloc(sizeof(t_touch_values));

    initValues(curValues);

    curTouches->touchInfoTab[index].pvalues = curValues;

    curValues->session_id = sessionID;
    curValues->where.x = argv[2]->f;
    curValues->where.y = argv[3]->f;
    curValues->where.z = argv[4]->f;
    curValues->speed.sx = argv[5]->f;
    curValues->speed.sy = argv[6]->f;
    curValues->speed.sz = argv[7]->f;
    curValues->motionAccel = argv[8]->f;

    //send_message(path,types,&argv[0]->s,argv[1]->i,argv[2]->f,argv[3]->f,argv[4]->f,argv[5]->f,argv[6]->f,argv[7]->f,argv[8]->f);
  /* example showing pulling the argument values out of the argv array */
  /*printf("%s <- i:%d\n\n", path, argv[1]->i);
  fflush(stdout);*/

  return 0;
}

//Handler for message /tuio/3Dcur set s x y z X Y Z m.
int tuio3Dcur_handler(const char *path, const char *types, lo_arg **argv, int argc,
                      void *data, void *user_data)
{

   	    // retrieve application data and fill current input info with OSC set message for 2Dcursors
    t_applicationData *appData = (t_applicationData *)user_data;

    // lumio sends 2DCUR so use 2D cursor handler function for testing algos

    int sessionID = argv[1]->i;
    p_touches curTouches = &(appData->input.touchdata[appData->input.currentIndex]);

    int nbTouches = curTouches->nbTouchInfo;

    // search for sessionID in ALIVE_LIST

    int index =0;
    int found = 0;

    while ((!found) && (index < nbTouches))
    {
            found = (sessionID == curTouches->alivelist[index]);
            index++;
    }

    if (!found)
    {
            printf("fatal error : sessionID not found in active Cursor list !\n");
            exit(-1);
    }
    else
    {
            index--;
            // update the cursor status to UPDATED_NOW
            if (curTouches->touchInfoTab[index].input_status == NOT_IN_CURRENT_BUNDLE)
            {
                    curTouches->touchInfoTab[index].input_status = UPDATED_NOW;
            }
    }

    // now copy other values in touch_info
    p_touch_values curValues = (p_touch_values)malloc(sizeof(t_touch_values));

    initValues(curValues);

    curTouches->touchInfoTab[index].pvalues = curValues;

    curValues->session_id = sessionID;
    curValues->where.x = argv[2]->f;
    curValues->where.y = argv[3]->f;
    curValues->where.z = argv[4]->f;
    curValues->speed.sx = argv[5]->f;
    curValues->speed.sy = argv[6]->f;
    curValues->speed.sz = argv[7]->f;
    curValues->motionAccel = argv[8]->f;
	//send_message(path,types,&argv[0]->s,argv[1]->i,argv[2]->f,argv[3]->f,argv[4]->f,argv[5]->f,argv[6]->f,argv[7]->f,argv[8]->f);
  /* example showing pulling the argument values out of the argv array */
  //printf("%s <- i:%d\n\n", path, argv[1]->i);
  //fflush(stdout);

  return 0;
}

//Handler for message /tuio/2Dobj set s i x y a X Y A m r.
int tuio2Dobj_handler(const char *path, const char *types, lo_arg **argv, int argc,
                      void *data, void *user_data)
{
	send_message(path,types,&argv[0]->s,argv[1]->i,argv[2]->i,argv[3]->f,argv[4]->f,argv[5]->f,argv[6]->f,argv[7]->f,argv[8]->f,argv[9]->f,argv[10]->f);
  /* example showing pulling the argument values out of the argv array */
  //printf("%s <- i:%d\n\n", path, argv[1]->i);
  //fflush(stdout);
  return 0;
}

//Handler for message /tuio/25Dobj set s i x y z a X Y Z A m r.
int tuio25Dobj_handler(const char *path, const char *types, lo_arg **argv, int argc,
                       void *data, void *user_data)
{
	send_message(path,types,&argv[0]->s,argv[1]->i,argv[2]->i,argv[3]->f,argv[4]->f,argv[5]->f,argv[6]->f,argv[7]->f,argv[8]->f,argv[9]->f,argv[10]->f,argv[11]->f,argv[12]->f);
  /* example showing pulling the argument values out of the argv array */
  //printf("%s <- i:%d\n\n", path, argv[1]->i);
  //fflush(stdout);
  return 0;
}

//Handler for message /tuio/3Dobj set s i x y z a b c X Y Z A B C m r.
int tuio3Dobj_handler(const char *path, const char *types, lo_arg **argv, int argc,
                      void *data, void *user_data)
{
	send_message(path,types,&argv[0]->s,argv[1]->i,argv[2]->i,argv[3]->f,argv[4]->f,argv[5]->f,argv[6]->f,argv[7]->f,argv[8]->f,argv[9]->f,argv[10]->f,argv[11]->f,argv[12]->f,argv[13]->f,argv[14]->f,argv[15]->f,argv[16]->f);
  /* example showing pulling the argument values out of the argv array */
  //printf("%s <- i:%d\n\n", path, argv[1]->i);
  //fflush(stdout);
  return 0;
}

//Handler for message /tuio/2Dblb set s x y a w h f X Y A m r.
int tuio2Dblb_handler(const char *path, const char *types, lo_arg **argv, int argc,
                      void *data, void *user_data)
{
	send_message(path,types,&argv[0]->s,argv[1]->i,argv[2]->f,argv[3]->f,argv[4]->f,argv[5]->f,argv[6]->f,argv[7]->f,argv[8]->f,argv[9]->f,argv[10]->f,argv[11]->f,argv[12]->f);
#ifdef VERBOSE
    /* example showing pulling the argument values out of the argv array */
    printf("%s <- i:%s %d %f%f\n\n", path, &argv[0]->s,argv[1]->i,argv[2]->f,argv[3]->f);
    fflush(stdout);
#endif
  return 0;
}

//Handler for message /tuio/25Dblb set s x y z a w h f X Y Z A m r.
int tuio25Dblb_handler(const char *path, const char *types, lo_arg **argv, int argc,
                       void *data, void *user_data)
{
	send_message(path,types,&argv[0]->s,argv[1]->i,argv[2]->f,argv[3]->f,argv[4]->f,argv[5]->f,argv[6]->f,argv[7]->f,argv[8]->f,argv[9]->f,argv[10]->f,argv[11]->f,argv[12]->f,argv[13]->f,argv[14]->f);
  /* example showing pulling the argument values out of the argv array */
  //printf("%s <- i:%d\n\n", path, argv[1]->i);
  //fflush(stdout);
  return 0;
}

//Handler for message /tuio/3Dblb set s x y z a b c w h d v X Y Z A B C m r.
int tuio3Dblb_handler(const char *path, const char *types, lo_arg **argv, int argc,
                      void *data, void *user_data)
{
	send_message(path,types,&argv[0]->s,argv[1]->i,argv[2]->f,argv[3]->f,argv[4]->f,argv[5]->f,argv[6]->f,argv[7]->f,argv[8]->f,argv[9]->f,argv[10]->f,argv[11]->f,argv[12]->f,argv[13]->f,argv[14]->f,argv[15]->f,argv[16]->f,argv[17]->f,argv[18]->f,argv[19]->f);
  /* example showing pulling the argument values out of the argv array */
  //printf("%s <- i:%d\n\n", path, argv[1]->i);
  //fflush(stdout);
  return 0;
}
